<?php
/**
 * Game_Resource
 *
 * Класс Game_Resource отвечает за обработку ресурсов
 *
 * @author Дмитрий Кузьма <kouzma.d@gmail.com>
 * @version 1.0
 */
class Game_Resource {
  
	protected static $_resourcesAmount = 4;
	protected static $_arrResourcesNames = array('Зерно', 'Дерево', 'Глина', 'Железо');
	protected $_arrResourcesData = array(); // Массив с информацией о ресурсах
	
	
	public function __construct($arrResources = array()) {
		if (is_subclass_of($arrResources, 'ActiveRecord')) $arrResources = $arrResources->tableFields;
		for ($i = 1; $i <= self::$_resourcesAmount; $i++) {
			 $this->_arrResourcesData[$i] = (
			 	isset($arrResources['resource_' . $i]) 
			 	? $arrResources['resource_' . $i] 
			 	: $arrResources[$i]
			 );
		}
  }
  
  /**
   * Метод получает двумерный массив данных для сохранения в БД
   * 
   */
  public function getDataForDatabase() {
  	$arrRet = array();
  	for ($i = 1; $i <= self::$_resourcesAmount; $i++) {
			 $arrRet['resource_' . $i] = $this->_arrResourcesData[$i];
		}
		return $arrRet;
  }
  
  
	/**
	 * Классический геттер
	 * 
	 */
	public function getResourcesData() {
		return $this->_arrResourcesData;
	}
	
	/**
	 * Получает название ресурса по его идентификатору
	 * 
	 * @param int $resourceId
	 */
	public static function getResourceName($resourceId) {
		return self::$_arrResourcesNames[$resourceId - 1];
	}

	/**
	 * Проверяет, достаточно ли ресурсов для оплаты того, что передается в метод
	 *
	 * @param Game_Resource $objResourceToPay
	 */
	public function isEnoughResources(Game_Resource $objResourceToPay) {
		$arrResourceToPay = $objResourceToPay->getResourcesData();
		for ($i = 1; $i <= self::$_resourcesAmount; $i++) {
			if ($this->_arrResourcesData[$i] < $arrResourceToPay[$i]) return false;
		}
		return true;
	}
	

	/**
	 * Проверяет, сколько раз хватит заплатить по такому количеству ресурсов
	 *
	 * @param Game_Resource $objResourceToPay
	 */
	public function howManyTimesEnoughResources(Game_Resource $objResourceToPay) {
		$arrResourceToPay = $objResourceToPay->getResourcesData();
		$timesAmount = null;
		for ($i = 1; $i <= self::$_resourcesAmount; $i++) {
			if (!($this->_arrResourcesData[$i])) return false;
			if ($timesAmount === null) $timesAmount = intval($this->_arrResourcesData[$i] / $arrResourceToPay[$i]);
			else $timesAmount = min($timesAmount, intval($this->_arrResourcesData[$i] / $arrResourceToPay[$i]));
		}
		return $timesAmount;
	}
	

	
	/**
	 * Возводит текущее значение ресурсов в степень
	 * 
	 * @param float $base - коэффициент роста
	 * @param float $exp - степень, в которую необходимо возвести
	 * 
	 * @return Game_Resource
	 */
	public function pow($base, $exp, $round = 5) {
		$arrResources = array();
		for ($i = 1; $i <= self::$_resourcesAmount; $i++) {
			$arrResources[$i] = $this->_arrResourcesData[$i] * pow($base, $exp);
			if ($round) $arrResources[$i] = round($arrResources[$i] / $round) * $round;
		}
		
		return new Game_Resource($arrResources);	
	}
	
	/**
	 * Метод вычетает ресурсы из текущего объекта
	 * 
	 * @param Game_Resource $objResource
	 * 
	 */
	public function decrease(Game_Resource $objResource) {
		$arrResources = $objResource->getResourcesData();
		for ($i = 1; $i <= self::$_resourcesAmount; $i++) {
			$this->_arrResourcesData[$i] -= $arrResources[$i];
		}
	}
	

	/**
	 * Метод вычетает ресурсы из текущего объекта
	 *
	 * @param Game_Resource $objResource
	 *
	 */
	public function increase(Game_Resource $objResource) {
		$arrResources = $objResource->getResourcesData();
		for ($i = 1; $i <= self::$_resourcesAmount; $i++) {
			$this->_arrResourcesData[$i] += $arrResources[$i];
		}
	}
	
	/**
	 * Увеличивает кол-во ресурсов в N раз
	 * 
	 * @param int $n
	 * 
	 * @return Game_Resource
	 */
	public function getMultipliedResources($n = 1) {
		$arrResources = array();
		for ($i = 1; $i <= self::$_resourcesAmount; $i++) {
			$arrResources[$i] = $this->_arrResourcesData[$i] *= $n;
		}
		return new Game_Resource($arrResources);
	}
	
	/**
	 * Получает сумму всех ресурсов
	 * 
	 * @return int
	 */
	public function getResourcesSum() {
		$sum = 0;
		for ($i = 1; $i <= self::$_resourcesAmount; $i++) {
			$sum += $this->_arrResourcesData[$i];
		}
		return $sum;
	}
	
	/**
	 * Получает новый объект ресурсов, который не превышает по сумме ресурсов лимит
	 * 
	 * @param int $limit - максимальное количество ресурсов, которым ограничиваемся
	 * 
	 * @return Game_Resource
	 */
	public function getResourcesByLimit($limit) {
		$currentSum = $this->getResourcesSum();
		// Если ресурсов меньше, чем лимит, то возвращаем все ресурсы 
		if ($limit >= $currentSum) return $this;

		$part = $limit / $currentSum;
		$arrInts = array();
		$arrFloats = array();
		$filledSum = 0;
		
		for ($i = 1; $i <= self::$_resourcesAmount; $i++) {
			$currentVal = $this->_arrResourcesData[$i] * $part;
			$arrInts[$i] = intval($currentVal);
			$arrFloats[$i] = $currentVal - $arrInts[$i];
			$filledSum += $arrInts[$i];
		}
		
		for ($k = $limit - $filledSum; $k > 0; $k--) {
			$maxFloat = 0;
			$currentFloat = 0;
			for ($i = 1; $i <= self::$_resourcesAmount; $i++) {
				if ($arrFloats[$i] > $maxFloat) {
					$maxFloat = $arrFloats[$i];
					$currentFloat = $i;
				}
			}
			$arrInts[$currentFloat]++;
			$arrFloats[$currentFloat] = 0;
		}
		
		return new Game_Resource($arrInts);
		
	}
}
?>